package mx.com.fractal.ristorante.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Table;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;

public class ParamSrcUtil {

	private static final Logger logger=Logger.getLogger(ParamSrcUtil.class);
	
	public static MapSqlParameterSource getParams(Object object) {
		Class<?> clazz=object.getClass();
		MapSqlParameterSource parameters=new MapSqlParameterSource();
		try{
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
			for(PropertyDescriptor propDesc : beanInfo.getPropertyDescriptors()){
				Method getter = propDesc.getReadMethod();
				if(getter!=null){
					Object value = getter.invoke(clazz.cast(object));
					if(isPrimitive(value)){
						parameters.addValue(propDesc.getName(), value);
					}
				}
			}
		} catch (Exception e) {
			logger.warn("Error al leer el los datos del bean: " + object, e);
		}
		logger.trace("Parametros --> " + parameters.getValues());
		return parameters;
	}
	
	public static String getWhereFromObject(Object object){
		StringBuilder and = new StringBuilder(" WHERE ");
		try{
			List<Field> fields = getFields(object.getClass());
			Object value=null;
			for(Field field : fields){
				field.setAccessible(true);
				value=field.get(object);
				if(value != null){
					Column column = field.getAnnotation(Column.class);
					if(column != null){
						and.append(column.name());
						and.append(" = ");
						and.append(":");
						and.append(field.getName());
						and.append(" and ");
					}
				}
				field.setAccessible(false);
			}
		}catch(Exception e){
			return "";
		}
		return and.substring(0, and.lastIndexOf("and"));
		
	}
	
	public static String getTableName(Class<?> clazz){
		Table table = clazz.getAnnotation(Table.class);
		Schema schema = clazz.getAnnotation(Schema.class);
		if(schema!=null && table != null){
			return new String(schema.value()+"."+table.name());
		}
		if(table != null){
			return table.name();
		}
		return null;
	}
	
	public static <T> void setValuesFromResultSet(T object,ResultSet rs){
		List<Field> fields = getFields(object.getClass());
		for(Field field : fields){
			Column column = field.getAnnotation(Column.class);
			if(column != null){
				try {
					field.setAccessible(true);
					Object valueDB = rs.getObject(column.name());
					if(!valueDB.getClass().isEnum()){
						field.set(object, valueDB);
					}
				} catch (SQLException e) {
					logger.trace("No se encuentra la columna en el Resultset: "+column.name());
				} catch (Exception e) {
					logger.error("Error al obtener los datos del result set",e);
				}finally{
					field.setAccessible(false);
				}
				
			}
		}
	}
	
	private static List<Field> getFields(Class<?> clazz){
		List<Field> fields = new LinkedList<Field>(Arrays.asList(clazz.getDeclaredFields()));
		if(clazz.getSuperclass() != null){
			List<Field> listFieldsSuper = Arrays.asList(
					clazz.getSuperclass().getDeclaredFields());
			fields.addAll(listFieldsSuper);
		}
		return fields;
	}
	
	private static boolean isPrimitive(Object object){
		if(object == null)
			return true;
		if(String.class.isInstance(object))
			return true;
		if(Short.class.isInstance(object))
			return true;
		if(Integer.class.isInstance(object))
			return true;
		if(Date.class.isInstance(object))
			return true;
		if(Float.class.isInstance(object))
			return true;
		if(Double.class.isInstance(object))
			return true;
		if(Character.class.isInstance(object))
			return true;
		
		return false;
		
	}
}
